﻿#define TODO
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Collections;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Xml.Serialization;

using common;

namespace server
{
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// <summary>
    ///  Szerver, egy előfordulása lehet, singleton
    /// </summary>
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////
    public sealed class Szerver
    {
        #region Variables

        private static Dictionary<int, KliensKezelo> _kliensek = new Dictionary<int, KliensKezelo>();
        
        private static int _kliensSzamlalo = 0;
        
        private static int _kliensekDictionaryID = 0;

        //ebben tároljuk az embereket
        private static List<Ember> _emberList = new List<Ember>();

        private static readonly Object _lock = new Object();

        private static TcpListener _tcpListener = null;

        private static Thread _listenThread = null;

        private static Szerver _instance = null;

        #endregion

        #region Constructors
        private Szerver()
        {  
            Log.logToFile("----Szerver constructor----",false);

            adatfelolvasas();
            serverListenStart();
        }
        #endregion

        #region Properties
        /// <summary>
        ///  Hálózati kliensek tárolója,
        ///  a kulcs minden bejegyzéssel növekszik eggyel
        /// </summary>
        public Dictionary<int, KliensKezelo> kliensek
        {
            get
            {
                return _kliensek;
            }
        }
        /// <summary>
        ///  a személyek listája, akik regisztrálva vannak
        /// </summary>
        public List<Ember> emberlist
        {
            get
            {
                return _emberList;
            }
        }
        /// <summary>
        ///  az egyke Szerver legyártása (egyszer, (lock alatt)) és a példány visszaadása
        /// </summary>
        public static Szerver instance
        {
            get
            {
                lock (_lock)
                {
                    if (_instance == null)
                    {
                        _instance = new Szerver();
                    }
                }

                return _instance;
            }
        }
        /// <summary>
        ///  ennyi hálózati kliens van a szerverre csatlakozva
        /// </summary>
        public int kliensSzamlalo
        {
            get { return _kliensSzamlalo; }
            set { _kliensSzamlalo = value; }
        }
        /// <summary>
        ///  ez lesz a <see cref="kliensek" /> listájához a kulcs 
        /// </summary>
        public int kliensekDictionaryID
        {
            get { return _kliensekDictionaryID; }
            set { _kliensekDictionaryID = value; }
        }
        #endregion

        #region Methods

        /// <summary>
        ///  HDD-ről olvasás
        /// </summary>
        public void adatfelolvasas()
        {
            XmlSerializer serializer = new XmlSerializer(typeof(List<Ember>));

            TextReader ReadFileStream = new StreamReader(Properties.Settings.Default.data_path + "Emberek.xml", false);

            _emberList = (List<Ember>)serializer.Deserialize(ReadFileStream);

            ReadFileStream.Close();
        }

        /// <summary>
        /// kliens program kezelő és az ő ID-je hozzáadása a <see cref="kliensek" /> listájához
        /// </summary>
        /// <param name="kk">ezt a KliensKezelőt-t adjuk hozzá a <see cref="kliensek" /> listájához</param>
        public void addKliensToKliensek(KliensKezelo kk)
        {
            lock (_lock)
            {
                Szerver.instance.kliensSzamlalo++;
                Szerver.instance.kliensekDictionaryID++;
                kk.kliensID.id = Szerver.instance.kliensekDictionaryID;
                Szerver.instance.kliensek.Add(kk.kliensID.id, kk);
            }
        }

        /// <summary>
        /// a szerver konzolos főmenüje
        /// </summary>
        public void menu()
        {
            int selector = 0;
            bool good = false;
            bool kilepes = false;
            
            while (!kilepes)
            {
                Console.Clear();
                Console.SetCursorPosition(0, 0);
                Console.WriteLine("1: tesztuzenet klienseknek");
                Console.WriteLine("2: adatok mentése");
                Console.WriteLine("0: kilépés");
                good = int.TryParse(Console.ReadLine(), out selector);

                if (good)
                {
                    switch (selector)
                    {
                        case 1:
                            Szerver.instance.sendAllClient();
                            break;
                        case 2:
                            Szerver.instance.adatKiiras();
                            break;
                        case 0:
                            kilepes = true;
                            break;
                        default:
                            break;
                    }
                }
                else
                {

                }
            }
        }

        /// <summary>
        /// minden kliensnek, broadcast üzenet
        /// </summary>
        public void sendAllClient()
        {
            foreach (KeyValuePair<int, KliensKezelo> kvp in _kliensek)
            {
                sendObjectToPC(kvp.Value.kliensID.id, "Üzenet a szervertől :)");
            }
        }

        /// <summary>
        /// adatok HDD-re
        /// </summary>
        public void adatKiiras()
        {
            XmlSerializer serializer = new XmlSerializer(typeof(List<Ember>));

            TextWriter WriteFileStream = new StreamWriter(Properties.Settings.Default.data_path + "Emberek.xml", false);

            serializer.Serialize(WriteFileStream, Szerver.instance.emberlist);

            WriteFileStream.Close();
        }

        /// <summary>
        /// egy kliens azonosító beléphet-e?
        /// </summary>
        /// <param name="klid">ezt a klienst vizsgáljuk</param>
        /// <returns>belépési jogosultság</returns>
        public bool loginElbiralas(KliensID klid)
        {
            bool ret = false;

            foreach (Ember e in _emberList)
            {
                if (e.userName == klid.userNev && e.password == klid.jelszo)
                {
                    ret = true;
                } 
            }
            return ret;
        }

        /// <summary>
        /// a szerver TCP/IP figyelését leállítása
        /// </summary>
        public void serverListenStop()
        {
            if (_tcpListener == null) { return; }
            try
            {
                _tcpListener.Stop();
            }
            catch {
                Console.WriteLine("----ServerListenStop error----"); 
            }
        }

        /// <summary>
        /// egy objektum küldése egy kliensnek
        /// </summary>
        /// <param name="pc">ennek a kliensnek küldjük</param>
        /// <param name="o">ezt az objektumot</param>
        public void sendObjectToPC(int pc, object o)
        {
            _kliensek[pc].sendObject(o);
        }

        /// <summary>
        /// a szerver TCP/IP figyelés elindítása, külön szálban
        /// </summary>
        public static void serverListenStart()
        {
            if (_tcpListener != null) return;
            _tcpListener = new TcpListener(IPAddress.Any, Properties.Settings.Default.listenport);
            _listenThread = new Thread(new ThreadStart(listenForClients));
            _listenThread.Name = "listenThread";
            _listenThread.IsBackground = true;
            _listenThread.Start();
        }

        /// <summary>
        /// a TCP/IP figyelés itt valósul meg, (végtelen ciklus) 
        /// </summary>
        public static void listenForClients()
        {
            try
            {
                _tcpListener.Start();
            }
            catch
            {
                Console.WriteLine("A porttal valami baj van, (foglalt?)"+ Properties.Settings.Default.listenport.ToString());

                return;
            }
            while (true)
            {
                try
                {
                    TcpClient Sclient = null;

                    Log.logToFile("----waiting for new TcpClient----",false);
                    Sclient = _tcpListener.AcceptTcpClient();

                    Log.logToFile("connecting from: " + Sclient.Client.RemoteEndPoint.ToString(),false);
                    //és kezeljük a klienst
                    KliensKezelo newConnection = new KliensKezelo(Sclient);
                }
                catch
                {
                    Console.WriteLine("Error... listen off");
                    _tcpListener.Stop();
                    _tcpListener = null;
                    _listenThread.Abort();
                    break;
                }
            }
        }


        #endregion
    }
}
